package com.ruoyi.system.service.impl;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.config.RabbitMQConfig;
import com.ruoyi.common.enums.OrderStatus;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.GetRequestDataUtils;
import com.ruoyi.common.utils.LogUtils;
import com.ruoyi.common.utils.exception.AjaxException;
import com.ruoyi.system.domain.SysChannel;
import com.ruoyi.system.domain.SysOrder;
import com.ruoyi.system.domain.SysUser;
import com.ruoyi.system.dto.RazorpayLoadDto;
import com.ruoyi.system.mapper.SysChannelMapper;
import com.ruoyi.system.mapper.SysChannelOutMapper;
import com.ruoyi.system.mapper.SysOrderMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.service.INotifyService;
import com.ruoyi.system.service.other.MessageEntity;
import com.ruoyi.system.service.other.MessageProducerService;
import com.ruoyi.system.service.other.SendService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author Ericcc
 * @version v0.01
 * @date 2021/3/11
 */
@Service
public class NotifyServiceImpl implements INotifyService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private SysOrderMapper sysOrderMapper;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SendService sendService;

    @Autowired
    private MessageProducerService messageProducerService;

    @Autowired
    private SysChannelMapper sysChannelMapper;

    @Autowired
    private SysChannelOutMapper sysChannelOutMapper;

    //注入RabbitMQ的模板
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    @Transactional
    public String razorpay(JSONObject requestJsonObject) {
        long time = System.currentTimeMillis();
        RazorpayLoadDto payload = requestJsonObject.getObject("payload", RazorpayLoadDto.class);
        if (payload == null) {
            throw new AjaxException("The callback abnormal");
        }
        String orderid = stringRedisTemplate.opsForValue().get("razorpay" + payload.getPayment().getEntity().getOrder_id());
        if (StringUtils.isNotBlank(orderid)) {
            return "250";
        }

        SysOrder order = sysOrderMapper.getByOrderCode(payload.getPayment().getEntity().getOrder_id());
        if (order == null) {
            return "250";
        }
        //模拟测试 暂时先注释
/*        if (order.getStatus() == OrderStatus.OK.getCode()) {
            return "250";
        }*/

        //查询商户
        SysUser merchant = sysUserMapper.selectUserById(order.getUserId());
        if (merchant == null) {
            throw new AjaxException("System error");
        }

        if (!"payment.captured".equals(requestJsonObject.getString("event"))) {
            return "250";
        }

        order.setSuccessTime(new Date());
        order.setOrderChannelCode(payload.getPayment().getEntity().getId());

/*        MessageEntity messageEntity = new MessageEntity();
        messageEntity.setKey("pay");
        messageEntity.setContent(JSONUtil.toJsonStr(order));
        messageProducerService.sendMeassage(JSONUtil.toJsonStr(messageEntity));*/
        MessageEntity messageEntity = new MessageEntity();
        messageEntity.setKey("pay");
        messageEntity.setContent(JSONUtil.toJsonStr(order));
        rabbitTemplate.convertAndSend(RabbitMQConfig.IPAY_TEST_EXCHANGE ,"ipay.mq" ,JSONUtil.toJsonStr(messageEntity));

        return "250";
    }

    @Override
    @Transactional
    public void cashfreeResult(TreeMap<String, String> params) {

        SysOrder order = sysOrderMapper.getByOrderCode(params.get("orderId"));
        if (order == null) {
            throw new AjaxException("order not exist");
        }

        SysChannel sysChannel = sysChannelMapper.selectSysChannelById(order.getChannelId());
        if (sysChannel == null) {
            throw new AjaxException("channel's info is not exist");
        }

        //验证sign
        LinkedHashMap<String, String> postData = new LinkedHashMap<>();

        postData.put("orderId", params.get("orderId"));
        postData.put("orderAmount", params.get("orderAmount"));
        postData.put("referenceId", params.get("referenceId"));
        postData.put("txStatus", params.get("txStatus"));
        postData.put("paymentMode", params.get("paymentMode"));
        postData.put("txMsg", params.get("txMsg"));
        postData.put("txTime", params.get("txTime"));
        String data = "";
        Set<String> keys = postData.keySet();

        for (String key : keys) {
            data = data + postData.get(key);
        }

        Mac sha256_HMAC = null;
        try {
            sha256_HMAC = Mac.getInstance("HmacSHA256");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecretKeySpec secret_key_spec = new
                SecretKeySpec(sysChannel.getChannelKey().getBytes(), "HmacSHA256");
        try {
            sha256_HMAC.init(secret_key_spec);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        String newsignature = java.util.Base64.getEncoder().encodeToString(sha256_HMAC.doFinal(data.getBytes()));
        String oldsignature = params.get("signature");
        if (!newsignature.equals(oldsignature)) {
            throw new AjaxException("验签异常");
        }

        //查询商户
        SysUser sysUser = sysUserMapper.selectUserById(order.getUserId());
        if (sysUser == null) {
            throw new AjaxException("user error");
        }

        String txStatus = params.get("txStatus");
        order.setOrderChannelCode(params.get("referenceId"));
        order.setSuccessTime(new Date());
        if ("SUCCESS".equals(txStatus)) {
            stringRedisTemplate.opsForValue().set("pay" + order.getOrderCode(), "SUCCESS", 72, TimeUnit.HOURS);
            MessageEntity messageEntity = new MessageEntity();
            messageEntity.setKey("pay");
            messageEntity.setContent(JSONUtil.toJsonStr(order));
            rabbitTemplate.convertAndSend(RabbitMQConfig.IPAY_TEST_EXCHANGE ,"ipay.mq" ,JSONUtil.toJsonStr(messageEntity));
            notifyChildenUser(order);
        }
    }


    private void notifyChildenUser(SysOrder sysOrder){
        LogUtils.log.debug("向商户发起回调");
        if (StringUtils.isBlank(sysOrder.getNotifyUrl())) {
            sysOrder.setStatus(OrderStatus.OK.getCode());
            if (sysOrderMapper.updateSysOrder(sysOrder) != 1) {
                throw new AjaxException("update order fail");
            }
        } else {
            //对商户回调
            //todo 设计商户回调

            sysOrder.setStatus(OrderStatus.OK.getCode());
            if (sysOrderMapper.updateSysOrder(sysOrder) != 1) {
                throw new AjaxException("update order fail");
            }
        }
    }
}
